package top.as.sean.common.rsa;

import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.jetbrains.annotations.NotNull;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;
import top.as.sean.common.exception.GlobalException;
import top.as.sean.common.response.RespStatus;

import javax.annotation.PostConstruct;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.security.KeyPair;
import java.util.stream.Collectors;

/**
 * 密码加密、解密、校验
 *
 * @author: ArchieSean
 * @create: 2023/1/30
 */
@Slf4j
@Component
public class RsaUtils {
    /**
     * 公钥文件名
     */
    private static final String PUBLIC_KEY = "public.key";

    /**
     * 私钥文件名
     */
    private static final String PRIVATE_KEY = "private.key";

    /**
     * RSA对象
     */
    private RSA rsa;

    /**
     * 初始化
     */
    @PostConstruct
    private void init() {
        log.info("--初始化RSA对象开始--");
        //获取私钥
        String privateKey = getPrivateKey();
        //获取公钥
        String publicKey = getPublicKey();
        rsa = new RSA(privateKey, publicKey);
        log.info("--初始化RSA对象成功--");
    }

    /**
     * 获取RSA对象
     * @return rsa
     */
    public RSA getRsa() {
        return rsa;
    }

    /**
     * 获取秘钥公共方法
     *
     * @param fileName 文件名
     * @return str
     */
    private  String getKey(String fileName) {
        ClassPathResource resource = new ClassPathResource(fileName);
        try {
            InputStreamReader reader = new InputStreamReader(resource.getInputStream());
            BufferedReader bufferedReader = new BufferedReader(reader);
            return bufferedReader.lines().collect(Collectors.joining("\n"));
        } catch (IOException e) {
            log.error("获取秘钥失败，原因：", e);
            return null;
        }
    }

    /**
     * 获取公钥
     *
     * @return string
     */
    private synchronized String getPublicKey() {
        return getKey(PUBLIC_KEY);
    }

    /**
     * 获取私钥
     *
     * @return string
     */
    private synchronized String getPrivateKey() {
        return getKey(PRIVATE_KEY);
    }

    /**
     * 校验密码合法性
     *
     * @param cntent 密码
     */
    public  void checkLegal(@NotNull String cntent) {
        try {
            rsa.decryptStr(cntent, KeyType.PrivateKey, CharsetUtil.CHARSET_UTF_8);
        } catch (Exception e) {
            log.error("合法性校验失败", e);
            throw new GlobalException(RespStatus.PASSWORD_NOT_LEGALITY);
        }
    }

    /**
     * 加密
     *
     * @param text 明文
     * @return str 密文
     */
    public  String encode(@NotNull String text) {
        try {
            return rsa.encryptBase64(text, CharsetUtil.CHARSET_UTF_8, KeyType.PublicKey);
        } catch (Exception e) {
            log.error("--加密失败--", e);
            throw new GlobalException(RespStatus.ENCODE_ERROR);
        }
    }

    /**
     * 解密
     *
     * @param text 密文
     * @return 明文
     */
    public  String decode(@NotNull String text) {
        try {
            return rsa.decryptStr(text, KeyType.PrivateKey, CharsetUtil.CHARSET_UTF_8);
        } catch (Exception e) {
            log.error("--解密失败--", e);
            throw new GlobalException(RespStatus.DECODE_ERROR);
        }
    }

    public static void main(String[] args) {
        KeyPair pair = SecureUtil.generateKeyPair("RSA",512);
        String privateKey = StrUtil.str(Base64.encodeBase64(pair.getPrivate().getEncoded()), CharsetUtil.CHARSET_UTF_8);
        System.out.println("privateKey:" + privateKey);
        String publicKey = StrUtil.str(Base64.encodeBase64(pair.getPublic().getEncoded()), CharsetUtil.CHARSET_UTF_8);
        System.out.println("publicKey:" + publicKey);
    }
}
